<?php

namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;

/**
 * 领取红包
 */
class Luck Extends model
{
    // 表名
    protected $table = 'luck';
    public $timestamps = false;
    protected $cache_sum_key = 'c';
    protected $queue_sum_key = 'q';
    protected $luck_total_money_use = 'luck_total_money_use';
    protected $redis;

    function __construct()
    {
        $this->redis = redis::connection();
    }

    public function getTradeNo($user_id )
    {
        $project_number = '1';  //项目编号

        //日期
        $time = ''.microtime(true);
        $arr = explode('.', $time) ;
        $d = substr(date('YmdHis',$arr[0]) , 2);

        $mc = isset( $arr[1] ) ? sprintf("%04d" ,$arr[1] ) : mt_rand(1000,9999);

        //                   2      2            12          8                             4
        $partner_trade_no = 'HSY'.$project_number.$d.sprintf("%08d" ,$user_id)  . $mc ;
        return $partner_trade_no ;
    }

    //奖品唯一序列码
    public function getLuckCode($luck_id , $luck_key)
    {
        //由luck_key 对应的一个字符 + 7位十六进制（ 9位十进制这个范围 100000000  - 268435455‬ 构成 ）

        $first = [];
        $first['no.4']   = 'T';
        $str1 = isset($first[$luck_key] ) ? $first[$luck_key] : 'J';

        $int1 = mt_rand(12,25).sprintf("%06d" ,$luck_id).mt_rand(1,9);

        return $str1 . strtoupper(dechex((int)$int1) ) ;
    }



    //容姐最漂亮 得最多的钱
    public function incTotalMoney($money)
    {
        //总金额
        Cache::increment( $this->luck_total_money_use , (int)( $money * 100 ) ); //分
    }


    //释放
    public function incQueue($money)
    {
        $config = config('luck.luck_config');

        //队列KEY
        $qk = $this->getQueueKey($config[$money] , $money ) ;
        return $this->redis->rPush( $qk  , '1' );
    }

    //减少一个队列
    public function decQueue($money,$config_info)
    {
//        $config = config('luck.luck_config');

        //队列KEY
        $qk = $this->getQueueKey($config_info[$money] , $money ) ;
        return $this->redis->blPop( $qk  , 1 ) ;
    }

    //获取当前队列KEY
    public function getQueueKey($config , $luck_key)
    {
        $time = time() ;

        // $time = strtotime('2018-12-12 12:00:01');
        // $time = strtotime('2018-12-13 12:00:01');

        foreach ($config['limit'] as $key => $value)
        {
            if( strtotime($value[0] ) <= $time &&  $time <= strtotime($value[1] ) )
            {
                return 'ygj2109_luck_sum_'.date('Y_m_d_His',strtotime($value[0])).'_'.$luck_key ;
            }
        }
        return 'ygj2109_luck_sum_' ;
    }

    //获取当前暂停查询数据KEY
    public function getCacheKey($config , $luck_key)
    {
        $time = time() ;
        // $time = strtotime('2018-12-12 12:00:01');
        // $time = strtotime('2019-02-28 12:00:01'); //-------------------------------------

        foreach ($config['limit'] as $key => $value)
        {

            if( strtotime($value[0] ) <= $time &&  $time <= strtotime($value[1] ) )
            {
                return 'ygj2109_luck_db_count_'.date('Y_m_d_His',strtotime($value[0])).'_'.$luck_key ;
            }
        }
        return 'ygj2109_luck_db_count_' ;
    }


    //获取当前概率
    public function getLimitPer($config)
    {
        $per = 0 ;
        $time = time() ;
        foreach ($config['limit'] as $key => $value)
        {
            if( strtotime($value[0] ) <= $time &&  $time <= strtotime($value[1] ) )
            {
                return $value[2];
            }
        }
        return $per ;
    }


    //获取当前限制数量
    public function getLimitSum($config)
    {
        $sum = 0 ;
        $time = time() ;
        foreach ($config['limit'] as $key => $value)
        {
            if( strtotime($value[0] ) <= $time &&  $time <= strtotime($value[1] ) )
            {
                return $value[3];
            }
        }
        return $sum ;
    }

    //获取当前事件段配置的每日限制数
    public function getLimitDaySum($config)
    {
        $sum = 0 ;
        $time = time() ;
        foreach ($config['limit'] as $key => $value)
        {
            if( strtotime($value[0] ) <= $time &&  $time <= strtotime($value[1] ) )
            {
                return $value[4];
            }
        }
        return $sum ;
    }



    //获取金额
    public function getLuck($user_id,$config_info)
    {
//        $config_info = config('luck.luck_config');

//        $luck_end_time = config('luck_end_time');

        //下面开始抽奖逻辑处理
        $push_sum    = 20;  //最大一次进队列多少个
        $to_push_sum = 0 ;  //实际一次进队列多少个
        //获取不同类型的奖品的已派的数量
        $can_sums = [];
        foreach ($config_info as $luck_key => $info)
        {
            //队列KEY
            $qk = $this->getQueueKey($info, $luck_key) ;
            $ck = $this->getCacheKey($info, $luck_key) ;

            $has_sum = $this->redis->llen( $qk );
            if( $has_sum <= 0 && !Cache::has($ck) )
            {
                //需要加入队列
                $use_sum = $this->where('luck_key',$luck_key)->whereIn('luck_status',[1,2,4])->count();
                //当前配置
                $max_sum = $this->getLimitSum($info) ;

                $has_sum = $max_sum - $use_sum ;

                $has_sum = $has_sum < 0 ? 0 : $has_sum ; //剩余多少

                $to_push_sum = $has_sum < $push_sum ? $has_sum : $push_sum ;

                //没有数量可派的时候，暂停查询操作了
                if($to_push_sum <= 0 )
                {
                    Cache::put($ck ,'lock' , 60*12 );
                }

                //重复操作禁止 锁
                usleep( mt_rand(5 , 50) * 1000 );
                if(!Cache::has('luck_sum_lock'.$luck_key))
                {
                    Cache::put('luck_sum_lock'.$luck_key , 'lock' , 0.5 );

                    $time1 = time() ;
//                    MyLog::write('info.luck.model',date('Y-m-d H:i:s',$time1).'|派放队列|奖品：'.$luck_key.'|总数：'.$max_sum.'|剩余：'.$has_sum.'|派放：'.$to_push_sum.'|正在进行'."\n");

                    for ( $i = 0; $i < $to_push_sum ; $i++)
                    {
                        $this->redis->rPush( $qk  , 1 );
                    }

                    $time2 = time() ;

//                    MyLog::write('info.luck.model',date('Y-m-d H:i:s',$time1).'|派放队列|奖品：'.$luck_key.'|总数：'.$max_sum.'|剩余：'.$has_sum.'|派放：'.$to_push_sum.'|派放完毕|用时：'.($time2 - $time1).'秒'."\n");

                    //是否超出,超出就要吐出来，以免超额d
                    $out_sum = $this->redis->llen( $qk ) - $to_push_sum  ;
                    for ($i = 0; $i < $out_sum ; $i++)
                    {
                        $this->redis->blPop( $qk  , 1 );
                    }

                    if($out_sum > 0 )
                    {
//                        MyLog::write('info.luck.model',date('Y-m-d H:i:s',$time1).'|派放队列|奖品：'.$luck_key.'|总数：'.$max_sum.'|剩余：'.$has_sum.'|派放：'.$push_sum.'|异常超出|处理：'.$out_sum .'个'."\n");
                    }

                    Cache::forget('luck_sum_lock'.$luck_key );
                }
            }
            else
            {
                $to_push_sum = $has_sum ;
            }

            //设置剩余
            $can_sums[$luck_key] = $to_push_sum ;
            $can_sums[$luck_key] = $can_sums[$luck_key] <= 0 ? 0 : $can_sums[$luck_key];
        }

        //获取配置默认的概率
        $per_lists = [];
        foreach ($config_info as $luck_key => $info)
        {
            $per_lists[$luck_key] = $this->getLimitPer($info);
        }

        $is_limit_day = false;

        //判断是否领完，如果已领完的类型，则不参与计算，并把概率平均分配到其他中去
        $del_per = 0 ;
        foreach ($can_sums as $luck_key => $sum)
        {
            if( $sum <= 0 )
            {
                $del_per += $per_lists[$luck_key] ;
                unset($per_lists[$luck_key]) ;
            }
            else
            {
                //每日限制处理
                $day_limit_sum = $this->getLimitDaySum($config_info[$luck_key] );
                if( $day_limit_sum !== 0 && $this->getTodaySum($luck_key) >= $day_limit_sum )
                {
                    $is_limit_day = true;
                    $del_per += $per_lists[$luck_key] ;
                    unset($per_lists[$luck_key]) ;

                }
            }


        }





        //如果一个都没有(奖品全派完)
        $now_has_type = count($per_lists);
        if($now_has_type <= 0 )
        {
            if($is_limit_day)
            {
                return -7 ;
            }

            return -1 ;
        }

        //分配新概率
        $avg_per = $del_per / $now_has_type;
        foreach ($per_lists as $luck_key => $value)
        {
            $per_lists[$luck_key] = $value + $avg_per ;
        }

        //新概率计算面积（长度）
        $win_base = 10000;
        $area_types = [];
        $limit = 0 ;
        foreach ($per_lists as $luck_key => $per)
        {
            $area_types[$luck_key][0] = $limit +1 ;

            $area_types[$luck_key][1] = $limit + (int)($win_base *$per );

            $limit = $area_types[$luck_key][1];
        }

        //概率都设置为0，所以没有中奖
        if($limit <= 0 )
        {
            return -301 ; //没中奖
        }

        //抽奖
        $is_win = mt_rand(1,$limit);
        $win_type = 0 ;
        // 中奖类型
        foreach ($area_types as $luck_key => $number)
        {
            if($number[0] <=  $is_win && $is_win <= $number[1] )
            {
                $win_type = $luck_key ;
                break;
            }
        }
        if( $win_type ===  0 )
        {
            return -302 ; //没中奖
        }


        //整体中奖概率
        $last_limit = (int) ( config('luck.luck_percent') * 1000 );
        if(mt_rand(0,1000) > $last_limit )
        {
            return -303 ; //不中
        }
        //队列减少一个
        $this->decQueue( $win_type ,$config_info);

        return $win_type;

    }

    //获取已派放总金额
    public function getTotalMoney()
    {
        //获取的是分
        $total = Cache::get($this->luck_total_money_use);

        if(empty( $total ))
        {
            $total = 0 ;
            $moneys = config('luck.luck_config');
            foreach ($moneys as $luck_key => $value)
            {
                $where = [];
                $where['luck_key']  = $luck_key;
                $where['luck_status'] = ['in',[1,2,3]] ;
                $sum = $this->where($where)->count();

                $total += (int) ($sum * ($luck_key * 100) );
            }

            Cache::put($this->luck_total_money_use , $total , 60 );
        }

        // 返回是元
        return $total / 100 ;

    }


    //红包发放队列
    public function sendQueue($luck_id)
    {
        return $this->redis->rPush('ygj2109_luck_send' , $luck_id);
    }


    // 获取一个
    public function getSend( $get_db )
    {
        $one = $this->redis->blPop('ygj2109_luck_send' , 1);
        if(empty($one) && $get_db )
        {
            //没有就查询数据库
            $where = [];
            $where['luck_status'] = 1 ;
//            $where['create_time']   = [ 'lt', time() - 5 ] ;
            $lists = self::query()->where($where)->select('id','user_id','openid','user_tel','luck_key','partner_trade_no','mall_id','type')->where($where)->limit(1000)->get()->toArray();

            if(!empty($lists ))
            {
                foreach ($lists as $key => $info)
                {
                    $this->redis->rPush('ygj2109_luck_send' , json_encode($info));
                }
                $one = $this->redis->blPop('ygj2109_luck_send' , 1);

                // // MyLog::write('info.script',date('Y-m-d H:i:s').'|红包发放|获取队列|方式：数据库列表|有数据'."\n");
            }
            else
            {
                //// MyLog::write('info.script',date('Y-m-d H:i:s').'|红包发放|获取队列|方式：数据库列表|无数据'."\n");
            }

        }
        else
        {
            //// MyLog::write('info.script',date('Y-m-d H:i:s').'|红包发放|获取队列|方式：队列'."\n");
        }
        return $one ? json_decode($one[1] ,true) : false ;

    }


    //获取今天派放数量
    public function getTodaySum($luck_key)
    {
        $key = 'luck_totay_send'.$luck_key.date('Ymd');
        $sum = Cache::get($key);

        if(empty($sum) )
        {
            //没有就查询数据库
            $where = [];
            $where['luck_key']    = $luck_key;
            $where['luck_status'] = ['in',[1,2,3]] ; //
            $where['create_time'] = [  'between',     [   strtotime(date('Y-m-d 00:00:00'))  , strtotime(date('Y-m-d 23:59:59') ) ]    ] ;
            $sum = self::query()->where($where)->count();

            Cache::put($key , $sum,10);

        }
        return $sum;
    }

    //增加今天派放数量一个
    public function incTodaySum($luck_key)
    {
        $key = 'luck_totay_send'.$luck_key.date('Ymd') ;
        return Cache::increment($key ,1 );
    }

    //减少今天派放数量一个
    public function decTodaySum($luck_key)
    {
        $key = 'luck_totay_send'.$luck_key.date('Ymd') ;
        return Cache::decrement($key ,1 );
    }



}

